Pythonμ SocketServer λͺ¨λμ μ¬μ©νμ¬ κ°λ ₯νκ³ νμ₯ κ°λ₯ν μμΌ μλ²λ₯Ό ꡬμΆνλ λ°©λ²μ λ°°μλλ€. ν΅μ¬ κ°λ , μ€μ μμ λ° μ¬λ¬ ν΄λΌμ΄μΈνΈ μ²λ¦¬λ₯Ό μν κ³ κΈ κΈ°μ μ μ΄ν΄λ³΄μΈμ.
μμΌ μλ² νλ μμν¬: Pythonμ SocketServer λͺ¨λμ λν μ€μ©μ μΈ κ°μ΄λ
μ€λλ μ μνΈ μ°κ²°λ μΈκ³μμ μμΌ νλ‘κ·Έλλ°μ λ€μν μ ν리μΌμ΄μ
κ³Ό μμ€ν
κ°μ ν΅μ μ κ°λ₯νκ² νλ λ° μ€μν μν μ ν©λλ€. Pythonμ SocketServer
λͺ¨λμ λ€νΈμν¬ μλ²λ₯Ό μμ±νλ κ°λ¨νκ³ κ΅¬μ‘°νλ λ°©λ²μ μ 곡νμ¬ κΈ°λ³Έ 볡μ‘μ±μ λλΆλΆ μΆμνν©λλ€. μ΄ κ°μ΄λλ μμΌ μλ² νλ μμν¬μ κΈ°λ³Έ κ°λ
μ μλ΄νκ³ Pythonμμ SocketServer
λͺ¨λμ μ€μ μ μ©μ μ€μ μ λ‘λλ€. κΈ°λ³Έ μλ² μ€μ , μ¬λ¬ ν΄λΌμ΄μΈνΈλ₯Ό λμμ μ²λ¦¬νκ³ νΉμ μꡬ μ¬νμ λ§λ μ¬λ°λ₯Έ μλ² μ νμ μ ννλ λ± λ€μν μΈ‘λ©΄μ λ€λ£° κ²μ
λλ€. κ°λ¨ν μ±ν
μ ν리μΌμ΄μ
μ ꡬμΆνλ 볡μ‘ν λΆμ° μμ€ν
μ ꡬμΆνλ SocketServer
λ₯Ό μ΄ν΄νλ κ²μ Pythonμμ λ€νΈμν¬ νλ‘κ·Έλλ°μ λ§μ€ν°νλ λ° μ€μν λ¨κ³μ
λλ€.
μμΌ μλ² μ΄ν΄νκΈ°
μμΌ μλ²λ λ€μ΄μ€λ ν΄λΌμ΄μΈνΈ μ°κ²°μ μν΄ νΉμ ν¬νΈμμ μμ λκΈ°νλ νλ‘κ·Έλ¨μ
λλ€. ν΄λΌμ΄μΈνΈκ° μ°κ²°λλ©΄ μλ²λ μ°κ²°μ μλ½νκ³ ν΅μ μ μν μ μμΌμ λ§λλλ€. μ΄λ₯Ό ν΅ν΄ μλ²λ μ¬λ¬ ν΄λΌμ΄μΈνΈλ₯Ό λμμ μ²λ¦¬ν μ μμ΅λλ€. Pythonμ SocketServer
λͺ¨λμ μμΌ κ΄λ¦¬ λ° μ°κ²° μ²λ¦¬μ νμ μμ€ μΈλΆ μ¬νμ μ²λ¦¬νμ¬ μ΄λ¬ν μλ²λ₯Ό ꡬμΆνκΈ° μν νλ μμν¬λ₯Ό μ 곡ν©λλ€.
ν΅μ¬ κ°λ
- μμΌ: μμΌμ λ€νΈμν¬μμ μ€νλλ λ νλ‘κ·Έλ¨ κ°μ μλ°©ν₯ ν΅μ λ§ν¬μ μλν¬μΈνΈμ λλ€. μ ν μκ³Ό μ μ¬ν©λλ€. ν νλ‘κ·Έλ¨μ΄ μμΌμ μ°κ²°νμ¬ μ 보λ₯Ό 보λ΄κ³ λ€λ₯Έ νλ‘κ·Έλ¨μ΄ λ€λ₯Έ μμΌμ μ°κ²°νμ¬ μ 보λ₯Ό λ°μ΅λλ€.
- ν¬νΈ: ν¬νΈλ λ€νΈμν¬ μ°κ²°μ΄ μμλκ³ λλλ κ°μ μ§μ μ λλ€. λ¨μΌ μμ€ν μμ μ€νλλ λ€μν μ ν리μΌμ΄μ λλ μλΉμ€λ₯Ό ꡬλ³νλ μ«μ μλ³μμ λλ€. μλ₯Ό λ€μ΄ HTTPλ μΌλ°μ μΌλ‘ ν¬νΈ 80μ μ¬μ©νκ³ HTTPSλ ν¬νΈ 443μ μ¬μ©ν©λλ€.
- IP μ£Όμ: IP(μΈν°λ· νλ‘ν μ½) μ£Όμλ ν΅μ μ μν΄ μΈν°λ· νλ‘ν μ½μ μ¬μ©νλ μ»΄ν¨ν° λ€νΈμν¬μ μ°κ²°λ κ° μ₯μΉμ ν λΉλ μ«μ λ μ΄λΈμ λλ€. λ€νΈμν¬μμ μ₯μΉλ₯Ό μλ³νμ¬ λ€λ₯Έ μ₯μΉκ° λ°μ΄ν°λ₯Ό λ³΄λΌ μ μλλ‘ ν©λλ€. IP μ£Όμλ μΈν°λ·μμ μ»΄ν¨ν°μ μ°νΈ μ£Όμμ κ°μ΅λλ€.
- TCP vs. UDP: TCP(μ μ‘ μ μ΄ νλ‘ν μ½) λ° UDP(μ¬μ©μ λ°μ΄ν°κ·Έλ¨ νλ‘ν μ½)λ λ€νΈμν¬ ν΅μ μ μ¬μ©λλ λ κ°μ§ κΈ°λ³Έ μ μ‘ νλ‘ν μ½μ λλ€. TCPλ μ°κ²° μ§ν₯μ μ΄λ©° μμ μ μ΄κ³ μμκ° μ§μ λκ³ μ€λ₯κ° κ²μ¬λ λ°μ΄ν° μ μ‘μ μ 곡ν©λλ€. UDPλ λΉμ°κ²°νμ΄λ©° λ λΉ λ₯΄μ§λ§ λ μμ μ μΈ μ μ‘μ μ 곡ν©λλ€. TCPμ UDP κ°μ μ νμ μ ν리μΌμ΄μ μ μꡬ μ¬νμ λ°λΌ λ€λ¦ λλ€.
Pythonμ SocketServer λͺ¨λ μκ°
SocketServer
λͺ¨λμ κΈ°λ³Έ μμΌ APIμ λν μμ μμ€ μΈν°νμ΄μ€λ₯Ό μ 곡νμ¬ Pythonμμ λ€νΈμν¬ μλ²λ₯Ό μμ±νλ νλ‘μΈμ€λ₯Ό λ¨μνν©λλ€. μμΌ κ΄λ¦¬μ λ§μ 볡μ‘μ±μ μΆμννμ¬ κ°λ°μκ° νμ μμ€ μΈλΆ μ¬ν보λ€λ μ ν리μΌμ΄μ
λ‘μ§μ μ§μ€ν μ μλλ‘ ν©λλ€. μ΄ λͺ¨λμ TCP μλ²(TCPServer
) λ° UDP μλ²(UDPServer
)λ₯Ό ν¬ν¨νμ¬ λ€μν μ νμ μλ²λ₯Ό λ§λλ λ° μ¬μ©ν μ μλ μ¬λ¬ ν΄λμ€λ₯Ό μ 곡ν©λλ€.
SocketServerμ μ£Όμ ν΄λμ€
BaseServer
:SocketServer
λͺ¨λμ λͺ¨λ μλ² ν΄λμ€μ κΈ°λ³Έ ν΄λμ€μ λλ€. μ°κ²° μμ λκΈ° λ° μμ² μ²λ¦¬μ κ°μ κΈ°λ³Έ μλ² λμμ μ μν©λλ€.TCPServer
: TCP(μ μ‘ μ μ΄ νλ‘ν μ½) μλ²λ₯Ό ꡬννλBaseServer
μ νμ ν΄λμ€μ λλ€. TCPλ μμ μ μ΄κ³ μμκ° μ§μ λκ³ μ€λ₯κ° κ²μ¬λ λ°μ΄ν° μ μ‘μ μ 곡ν©λλ€.UDPServer
: UDP(μ¬μ©μ λ°μ΄ν°κ·Έλ¨ νλ‘ν μ½) μλ²λ₯Ό ꡬννλBaseServer
μ νμ ν΄λμ€μ λλ€. UDPλ λΉμ°κ²°νμ΄λ©° λ λΉ λ₯΄μ§λ§ λ μμ μ μΈ λ°μ΄ν° μ μ‘μ μ 곡ν©λλ€.BaseRequestHandler
: μμ² μ²λ¦¬κΈ° ν΄λμ€μ κΈ°λ³Έ ν΄λμ€μ λλ€. μμ² μ²λ¦¬κΈ°λ κ°λ³ ν΄λΌμ΄μΈνΈ μμ²μ μ²λ¦¬νλ μν μ ν©λλ€.StreamRequestHandler
: TCP μμ²μ μ²λ¦¬νλBaseRequestHandler
μ νμ ν΄λμ€μ λλ€. μ€νΈλ¦ΌμΌλ‘ ν΄λΌμ΄μΈνΈ μμΌμ λ°μ΄ν°λ₯Ό μ½κ³ μ°λ λ° νΈλ¦¬ν λ©μλλ₯Ό μ 곡ν©λλ€.DatagramRequestHandler
: UDP μμ²μ μ²λ¦¬νλBaseRequestHandler
μ νμ ν΄λμ€μ λλ€. λ°μ΄ν°κ·Έλ¨(λ°μ΄ν° ν¨ν·)μ μμ νκ³ λ³΄λ΄λ λ©μλλ₯Ό μ 곡ν©λλ€.
κ°λ¨ν TCP μλ² λ§λ€κΈ°
λ€μ΄μ€λ μ°κ²°μ μμ λκΈ°νκ³ μμ λ λ°μ΄ν°λ₯Ό ν΄λΌμ΄μΈνΈμ λ€μ μμ½νλ κ°λ¨ν TCP μλ²λ₯Ό λ§λ€μ΄ λ³΄κ² μ΅λλ€. μ΄ μμ λ SocketServer
μ ν리μΌμ΄μ
μ κΈ°λ³Έ ꡬ쑰λ₯Ό 보μ¬μ€λλ€.
μμ : μμ½ μλ²
κΈ°λ³Έ μμ½ μλ²μ μ½λλ λ€μκ³Ό κ°μ΅λλ€.
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The request handler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
# just send back the same data you received.
self.request.sendall(self.data)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
# Create the server, binding to localhost on port 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
μ€λͺ :
SocketServer
λͺ¨λμ κ°μ Έμ΅λλ€.SocketServer.BaseRequestHandler
μμ μμνλ μμ² μ²λ¦¬κΈ° ν΄λμ€MyTCPHandler
λ₯Ό μ μν©λλ€.handle()
λ©μλλ μμ² μ²λ¦¬κΈ°μ ν΅μ¬μ λλ€. ν΄λΌμ΄μΈνΈκ° μλ²μ μ°κ²°λ λλ§λ€ νΈμΆλ©λλ€.handle()
λ©μλ λ΄μμself.request.recv(1024)
λ₯Ό μ¬μ©νμ¬ ν΄λΌμ΄μΈνΈλ‘λΆν° λ°μ΄ν°λ₯Ό μμ ν©λλ€. μ΄ μμ μμλ μμ λλ μ΅λ λ°μ΄ν°λ₯Ό 1024λ°μ΄νΈλ‘ μ νν©λλ€.- ν΄λΌμ΄μΈνΈμ μ£Όμμ μμ λ λ°μ΄ν°λ₯Ό μ½μμ μΆλ ₯ν©λλ€.
self.request.sendall(self.data)
λ₯Ό μ¬μ©νμ¬ μμ λ λ°μ΄ν°λ₯Ό ν΄λΌμ΄μΈνΈμ λ€μ 보λ λλ€.if __name__ == "__main__":
λΈλ‘μμTCPServer
μΈμ€ν΄μ€λ₯Ό λ§λ€μ΄ localhost μ£Όμμ ν¬νΈ 9999μ λ°μΈλ©ν©λλ€.- κ·Έλ° λ€μ
server.serve_forever()
λ₯Ό νΈμΆνμ¬ μλ²λ₯Ό μμνκ³ νλ‘κ·Έλ¨μ΄ μ€λ¨λ λκΉμ§ μ€ν μνλ₯Ό μ μ§ν©λλ€.
μμ½ μλ² μ€ν
μμ½ μλ²λ₯Ό μ€ννλ €λ©΄ μ½λλ₯Ό νμΌ(μ: echo_server.py
)μ μ μ₯νκ³ λͺ
λ Ήμ€μμ μ€νν©λλ€.
python echo_server.py
μλ²λ ν¬νΈ 9999μμ μ°κ²°μ μμ νκΈ° μμν©λλ€. κ·Έλ° λ€μ telnet
λλ netcat
κ³Ό κ°μ ν΄λΌμ΄μΈνΈ νλ‘κ·Έλ¨μ μ¬μ©νμ¬ μλ²μ μ°κ²°ν μ μμ΅λλ€. μλ₯Ό λ€μ΄ netcat
μ μ¬μ©νλ κ²½μ°:
nc localhost 9999
netcat
ν΄λΌμ΄μΈνΈμ μ
λ ₯νλ λͺ¨λ λ΄μ©μ μλ²λ‘ μ μ‘λμ΄ λ€μ μμ½λ©λλ€.
μ¬λ¬ ν΄λΌμ΄μΈνΈ λμ μ²λ¦¬
μμ κΈ°λ³Έ μμ½ μλ²λ ν λ²μ νλμ ν΄λΌμ΄μΈνΈλ§ μ²λ¦¬ν μ μμ΅λλ€. 첫 λ²μ§Έ ν΄λΌμ΄μΈνΈκ° μμ§ μλΉμ€ μ€μΈ λμ λ λ²μ§Έ ν΄λΌμ΄μΈνΈκ° μ°κ²°λλ©΄ λ λ²μ§Έ ν΄λΌμ΄μΈνΈλ 첫 λ²μ§Έ ν΄λΌμ΄μΈνΈκ° μ°κ²°μ λμ λκΉμ§ κΈ°λ€λ €μΌ ν©λλ€. μ΄κ²μ λλΆλΆμ μ€μ μ ν리μΌμ΄μ μ μ΄μμ μ΄μ§ μμ΅λλ€. μ¬λ¬ ν΄λΌμ΄μΈνΈλ₯Ό λμμ μ²λ¦¬νκΈ° μν΄ μ€λ λ© λλ ν¬νΉμ μ¬μ©ν μ μμ΅λλ€.μ€λ λ©
μ€λ λ©μ μ¬μ©νλ©΄ λμΌν νλ‘μΈμ€ λ΄μμ μ¬λ¬ ν΄λΌμ΄μΈνΈλ₯Ό λμμ μ²λ¦¬ν μ μμ΅λλ€. κ° ν΄λΌμ΄μΈνΈ μ°κ²°μ λ³λμ μ€λ λμμ μ²λ¦¬λλ―λ‘ μλ²λ λ€λ₯Έ ν΄λΌμ΄μΈνΈκ° μλΉμ€λλ λμ μ μ°κ²°μ κ³μ μμ ν μ μμ΅λλ€. SocketServer
λͺ¨λμ μ€λ λ©μ νμ±ννκΈ° μν΄ μλ² ν΄λμ€μ ν¨κ» νΌν©ν μ μλ ThreadingMixIn
ν΄λμ€λ₯Ό μ 곡ν©λλ€.
μμ : μ€λ λ μμ½ μλ²
import SocketServer
import threading
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
self.request.sendall(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
# ... (Your main thread logic here, e.g., simulating client connections)
# For example, to keep the main thread alive:
# while True:
# pass # Or perform other tasks
server.shutdown()
μ€λͺ :
threading
λͺ¨λμ κ°μ Έμ΅λλ€.SocketServer.BaseRequestHandler
μμ μμνλThreadedTCPRequestHandler
ν΄λμ€λ₯Ό λ§λλλ€.handle()
λ©μλλ μ΄μ μμ μ μ μ¬νμ§λ§ μλ΅μ νμ¬ μ€λ λμ μ΄λ¦λ ν¬ν¨ν©λλ€.SocketServer.ThreadingMixIn
κ³ΌSocketServer.TCPServer
λͺ¨λμμ μμνλThreadedTCPServer
ν΄λμ€λ₯Ό λ§λλλ€. μ΄ λ―Ήμ€μΈμ μλ²μ λν μ€λ λ©μ νμ±νν©λλ€.if __name__ == "__main__":
λΈλ‘μμThreadedTCPServer
μΈμ€ν΄μ€λ₯Ό λ§λ€κ³ λ³λμ μ€λ λμμ μμν©λλ€. μ΄λ₯Ό ν΅ν΄ μ£Ό μ€λ λλ λ°±κ·ΈλΌμ΄λμμ μλ²κ° μ€νλλ λμ κ³μ μ€νλ μ μμ΅λλ€.
μ΄μ μ΄ μλ²λ μ¬λ¬ ν΄λΌμ΄μΈνΈ μ°κ²°μ λμμ μ²λ¦¬ν μ μμ΅λλ€. κ° μ°κ²°μ λ³λμ μ€λ λμμ μ²λ¦¬λλ―λ‘ μλ²λ μ¬λ¬ ν΄λΌμ΄μΈνΈμ λμμ μλ΅ν μ μμ΅λλ€.
ν¬νΉ
ν¬νΉμ μ¬λ¬ ν΄λΌμ΄μΈνΈλ₯Ό λμμ μ²λ¦¬νλ λ λ€λ₯Έ λ°©λ²μ
λλ€. μ ν΄λΌμ΄μΈνΈ μ°κ²°μ΄ μμ λλ©΄ μλ²λ μ νλ‘μΈμ€λ₯Ό ν¬ν¬νμ¬ μ°κ²°μ μ²λ¦¬ν©λλ€. κ° νλ‘μΈμ€λ μ체 λ©λͺ¨λ¦¬ 곡κ°μ κ°μ§λ―λ‘ νλ‘μΈμ€λ μλ‘ κ²©λ¦¬λ©λλ€. SocketServer
λͺ¨λμ ν¬νΉμ νμ±ννκΈ° μν΄ μλ² ν΄λμ€μ ν¨κ» νΌν©ν μ μλ ForkingMixIn
ν΄λμ€λ₯Ό μ 곡ν©λλ€. μ°Έκ³ : ν¬νΉμ μΌλ°μ μΌλ‘ Unix κ³μ΄ μμ€ν
(Linux, macOS)μμ μ¬μ©λλ©° Windows νκ²½μμλ μ¬μ©ν μ μκ±°λ μ ν©νμ§ μμ μ μμ΅λλ€.
μμ : ν¬νΉ μμ½ μλ²
import SocketServer
import os
class ForkingTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
pid = os.getpid()
response = "PID {}: {}".format(pid, data)
self.request.sendall(response)
class ForkingTCPServer(SocketServer.ForkingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = ForkingTCPServer((HOST, PORT), ForkingTCPRequestHandler)
ip, port = server.server_address
server.serve_forever()
μ€λͺ :
os
λͺ¨λμ κ°μ Έμ΅λλ€.SocketServer.BaseRequestHandler
μμ μμνλForkingTCPRequestHandler
ν΄λμ€λ₯Ό λ§λλλ€.handle()
λ©μλλ μλ΅μ νλ‘μΈμ€ ID(PID)λ₯Ό ν¬ν¨ν©λλ€.SocketServer.ForkingMixIn
κ³ΌSocketServer.TCPServer
λͺ¨λμμ μμνλForkingTCPServer
ν΄λμ€λ₯Ό λ§λλλ€. μ΄ λ―Ήμ€μΈμ μλ²μ λν ν¬νΉμ νμ±νν©λλ€.if __name__ == "__main__":
λΈλ‘μμForkingTCPServer
μΈμ€ν΄μ€λ₯Ό λ§λ€κ³server.serve_forever()
λ₯Ό μ¬μ©νμ¬ μμν©λλ€. κ° ν΄λΌμ΄μΈνΈ μ°κ²°μ λ³λμ νλ‘μΈμ€μμ μ²λ¦¬λ©λλ€.
ν΄λΌμ΄μΈνΈκ° μ΄ μλ²μ μ°κ²°λλ©΄ μλ²λ μ νλ‘μΈμ€λ₯Ό ν¬ν¬νμ¬ μ°κ²°μ μ²λ¦¬ν©λλ€. κ° νλ‘μΈμ€μλ μ체 PIDκ° μμΌλ―λ‘ μ°κ²°μ΄ λ€λ₯Έ νλ‘μΈμ€μμ μ²λ¦¬λκ³ μμμ νμΈν μ μμ΅λλ€.
μ€λ λ©κ³Ό ν¬νΉ μ€μμ μ ν
μ€λ λ©κ³Ό ν¬νΉ μ€μμ μ ννλ κ²μ μ΄μ 체μ , μ ν리μΌμ΄μ μ νΉμ± λ° μ¬μ© κ°λ₯ν 리μμ€λ₯Ό ν¬ν¨ν μ¬λ¬ μμμ λ°λΌ λ€λ¦ λλ€. μ£Όμ κ³ λ € μ¬νμ λν μμ½μ λ€μκ³Ό κ°μ΅λλ€.
- μ΄μ 체μ : ν¬νΉμ μΌλ°μ μΌλ‘ Unix κ³μ΄ μμ€ν μμ μ νΈλλ λ°λ©΄ μ€λ λ©μ Windowsμμ λ μΌλ°μ μ λλ€.
- 리μμ€ μλΉ: κ° νλ‘μΈμ€μλ μ체 λ©λͺ¨λ¦¬ 곡κ°μ΄ μμΌλ―λ‘ ν¬νΉμ μ€λ λ©λ³΄λ€ λ λ§μ 리μμ€λ₯Ό μλΉν©λλ€. μ€λ λ©μ λ©λͺ¨λ¦¬ 곡κ°μ 곡μ νλ―λ‘ λ ν¨μ¨μ μΌ μ μμ§λ§ κ²½ν© μ‘°κ±΄ λ° κΈ°ν λμμ± λ¬Έμ λ₯Ό λ°©μ§νκΈ° μν΄ μ μ€ν λκΈ°νκ° νμν©λλ€.
- 볡μ‘μ±: νΉν 곡μ 리μμ€λ₯Ό μ²λ¦¬ν λ μ€λ λ©μ ν¬νΉλ³΄λ€ ꡬννκ³ λλ²κΉ νλ λ° λ 볡μ‘ν μ μμ΅λλ€.
- νμ₯μ±: ν¬νΉμ μ¬λ¬ CPU μ½μ΄λ₯Ό λ ν¨κ³Όμ μΌλ‘ νμ©ν μ μμΌλ―λ‘ κ²½μ°μ λ°λΌ μ€λ λ©λ³΄λ€ λ μ νμ₯ν μ μμ΅λλ€. κ·Έλ¬λ νλ‘μΈμ€ μμ± λ° κ΄λ¦¬μ μ€λ²ν€λλ νμ₯μ±μ μ νν μ μμ΅λλ€.
μΌλ°μ μΌλ‘ Unix κ³μ΄ μμ€ν μμ κ°λ¨ν μ ν리μΌμ΄μ μ ꡬμΆνλ κ²½μ° ν¬νΉμ΄ μ’μ μ νμΌ μ μμ΅λλ€. λ 볡μ‘ν μ ν리μΌμ΄μ μ ꡬμΆνκ±°λ Windowsλ₯Ό νκ²ν νλ κ²½μ° μ€λ λ©μ΄ λ μ ν©ν μ μμ΅λλ€. λν νκ²½μ 리μμ€ μ μ½ μ‘°κ±΄κ³Ό μ ν리μΌμ΄μ μ μ μ¬μ νμ₯μ± μꡬ μ¬νμ κ³ λ €νλ κ²μ΄ μ€μν©λλ€. νμ₯μ±μ΄ λ°μ΄λ μ ν리μΌμ΄μ μ κ²½μ° λ λμ μ±λ₯κ³Ό 리μμ€ νμ©λ₯ μ μ 곡ν μ μλ `asyncio`μ κ°μ λΉλκΈ° νλ μμν¬λ₯Ό κ³ λ €νμΈμ.
κ°λ¨ν UDP μλ² λ§λ€κΈ°
UDP(μ¬μ©μ λ°μ΄ν°κ·Έλ¨ νλ‘ν μ½)λ TCPλ³΄λ€ λΉ λ₯΄μ§λ§ λ μμ μ μΈ λ°μ΄ν° μ μ‘μ μ 곡νλ λΉμ°κ²°ν νλ‘ν μ½μ
λλ€. UDPλ μ€νΈλ¦¬λ° λ―Έλμ΄ λ° μ¨λΌμΈ κ²μκ³Ό κ°μ΄ μλκ° μμ μ±λ³΄λ€ λ μ€μν μ ν리μΌμ΄μ
μ μμ£Ό μ¬μ©λ©λλ€. SocketServer
λͺ¨λμ UDP μλ²λ₯Ό λ§λ€κΈ° μν UDPServer
ν΄λμ€λ₯Ό μ 곡ν©λλ€.
μμ : UDP μμ½ μλ²
import SocketServer
class MyUDPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print "{} wrote:".format(self.client_address[0])
print data
socket.sendto(data, self.client_address)
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.UDPServer((HOST, PORT), MyUDPHandler)
server.serve_forever()
μ€λͺ :
MyUDPHandler
ν΄λμ€μhandle()
λ©μλλ ν΄λΌμ΄μΈνΈλ‘λΆν° λ°μ΄ν°λ₯Ό μμ ν©λλ€. TCPμ λ¬λ¦¬ UDP λ°μ΄ν°λ λ°μ΄ν°κ·Έλ¨(λ°μ΄ν° ν¨ν·)μΌλ‘ μμ λ©λλ€.self.request
μμ±μ λ°μ΄ν°μ μμΌμ ν¬ν¨νλ ννμ λλ€.self.request[0]
μ μ¬μ©νμ¬ λ°μ΄ν°λ₯Ό μΆμΆνκ³self.request[1]
μ μ¬μ©νμ¬ μμΌμ μΆμΆν©λλ€.socket.sendto(data, self.client_address)
λ₯Ό μ¬μ©νμ¬ μμ λ λ°μ΄ν°λ₯Ό ν΄λΌμ΄μΈνΈμ λ€μ 보λ λλ€.
μ΄ μλ²λ ν΄λΌμ΄μΈνΈλ‘λΆν° UDP λ°μ΄ν°κ·Έλ¨μ μμ νκ³ λ³΄λΈ μ¬λμκ² λ€μ μμ½ν©λλ€.
κ³ κΈ κΈ°μ
λ€μν λ°μ΄ν° νμ μ²λ¦¬
λ§μ μ€μ μ ν리μΌμ΄μ
μμ JSON, XML λλ νλ‘ν μ½ λ²νΌμ κ°μ λ€μν λ°μ΄ν° νμμ μ²λ¦¬ν΄μΌ ν©λλ€. Pythonμ λ΄μ₯ λͺ¨λ λλ νμ¬ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λ°μ΄ν°λ₯Ό μ§λ ¬ννκ³ μμ§λ ¬νν μ μμ΅λλ€. μλ₯Ό λ€μ΄ json
λͺ¨λμ μ¬μ©νμ¬ JSON λ°μ΄ν°λ₯Ό μ²λ¦¬ν μ μμ΅λλ€.
import SocketServer
import json
class JSONTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024).strip()
json_data = json.loads(data)
print "Received JSON data:", json_data
# Process the JSON data
response_data = {"status": "success", "message": "Data received"}
response_json = json.dumps(response_data)
self.request.sendall(response_json)
except ValueError as e:
print "Invalid JSON data received: {}".format(e)
self.request.sendall(json.dumps({"status": "error", "message": "Invalid JSON"}))
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), JSONTCPHandler)
server.serve_forever()
μ΄ μμ λ ν΄λΌμ΄μΈνΈλ‘λΆν° JSON λ°μ΄ν°λ₯Ό μμ νκ³ json.loads()
λ₯Ό μ¬μ©νμ¬ κ΅¬λ¬Έ λΆμνκ³ μ²λ¦¬ν λ€μ json.dumps()
λ₯Ό μ¬μ©νμ¬ JSON μλ΅μ ν΄λΌμ΄μΈνΈμ λ€μ 보λ
λλ€. μλͺ»λ JSON λ°μ΄ν°λ₯Ό catchνκΈ° μν μ€λ₯ μ²λ¦¬ κΈ°λ₯μ΄ ν¬ν¨λμ΄ μμ΅λλ€.
μΈμ¦ ꡬν
보μ μ ν리μΌμ΄μ μ κ²½μ° ν΄λΌμ΄μΈνΈμ IDλ₯Ό νμΈνκΈ° μν΄ μΈμ¦μ ꡬνν΄μΌ ν©λλ€. μ¬μ©μ μ΄λ¦/μνΈ μΈμ¦, API ν€ λλ λμ§νΈ μΈμ¦μμ κ°μ λ€μν λ°©λ²μ μ¬μ©νμ¬ μνν μ μμ΅λλ€. λ€μμ μ¬μ©μ μ΄λ¦/μνΈ μΈμ¦μ κ°λ¨ν μμ λλ€.
import SocketServer
import hashlib
# Replace with a secure way to store passwords (e.g., using bcrypt)
USER_CREDENTIALS = {
"user1": "password123",
"user2": "secure_password"
}
class AuthTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
# Authentication logic
username = self.request.recv(1024).strip()
password = self.request.recv(1024).strip()
if username in USER_CREDENTIALS and USER_CREDENTIALS[username] == password:
print "User {} authenticated successfully".format(username)
self.request.sendall("Authentication successful")
# Proceed with handling the client request
# (e.g., receive further data and process it)
else:
print "Authentication failed for user {}".format(username)
self.request.sendall("Authentication failed")
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), AuthTCPHandler)
server.serve_forever()
μ€μ 보μ μ°Έκ³ μ¬ν: μμ μλ λ°λͺ¨μ©μΌ λΏμ΄λ©° μμ νμ§ μμ΅λλ€. μνΈλ₯Ό μΌλ° ν μ€νΈλ‘ μ μ₯νμ§ λ§μμμ€. μ μ₯νκΈ° μ μ bcrypt λλ Argon2μ κ°μ κ°λ ₯ν μνΈ ν΄μ± μκ³ λ¦¬μ¦μ μ¬μ©νμ¬ μνΈλ₯Ό ν΄μ±νμμμ€. λν νλ‘λμ νκ²½μμλ OAuth 2.0 λλ JWT(JSON μΉ ν ν°)μ κ°μ λ³΄λ€ κ°λ ₯ν μΈμ¦ λ©μ»€λμ¦μ μ¬μ©νλ κ²μ΄ μ’μ΅λλ€.
λ‘κΉ λ° μ€λ₯ μ²λ¦¬
μ μ ν λ‘κΉ
λ° μ€λ₯ μ²λ¦¬λ μλ²λ₯Ό λλ²κΉ
νκ³ μ μ§ κ΄λ¦¬νλ λ° νμμ μ
λλ€. Pythonμ logging
λͺ¨λμ μ¬μ©νμ¬ μ΄λ²€νΈ, μ€λ₯ λ° κΈ°ν κ΄λ ¨ μ 보λ₯Ό κΈ°λ‘ν©λλ€. μμΈλ₯Ό μ μμ μΌλ‘ μ²λ¦¬νκ³ μλ²κ° μΆ©λνμ§ μλλ‘ ν¬κ΄μ μΈ μ€λ₯ μ²λ¦¬λ₯Ό ꡬνν©λλ€. λ¬Έμ λ₯Ό ν¨κ³Όμ μΌλ‘ μ§λ¨νκΈ°μ μΆ©λΆν μ 보λ₯Ό νμ κΈ°λ‘νμμμ€.
import SocketServer
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class LoggingTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(1024).strip()
logging.info("Received data from {}: {}".format(self.client_address[0], data))
self.request.sendall(data)
except Exception as e:
logging.exception("Error handling request from {}: {}".format(self.client_address[0], e))
self.request.sendall("Error processing request")
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), LoggingTCPHandler)
server.serve_forever()
μ΄ μμ λ λ€μ΄μ€λ μμ²μ λν μ 보μ μμ² μ²λ¦¬ μ€μ λ°μνλ μ€λ₯λ₯Ό κΈ°λ‘νλλ‘ λ‘κΉ
μ ꡬμ±ν©λλ€. logging.exception()
λ©μλλ λλ²κΉ
μ μ μ©ν μ μλ μ 체 μ€ν μΆμ μΌλ‘ μμΈλ₯Ό κΈ°λ‘νλ λ° μ¬μ©λ©λλ€.
SocketServerμ λμ
SocketServer
λͺ¨λμ μμΌ νλ‘κ·Έλλ°μ λ°°μ°κΈ° μν μ’μ μμμ μ΄μ§λ§ νΉν κ³ μ±λ₯ λ° νμ₯ κ°λ₯ν μ ν리μΌμ΄μ
μ κ²½μ° λͺ κ°μ§ μ ν μ¬νμ΄ μμ΅λλ€. λͺ κ°μ§ μΈκΈ° μλ λμμ λ€μκ³Ό κ°μ΅λλ€.
- asyncio: Pythonμ κΈ°λ³Έ μ 곡 λΉλκΈ° I/O νλ μμν¬μ
λλ€.
asyncio
λ μ½λ£¨ν΄ λ° μ΄λ²€νΈ 루νλ₯Ό μ¬μ©νμ¬ μ¬λ¬ λμ μ°κ²°μ μ²λ¦¬νλ λ³΄λ€ ν¨μ¨μ μΈ λ°©λ²μ μ 곡ν©λλ€. μΌλ°μ μΌλ‘ λμ λμμ±μ΄ νμν μ΅μ μ ν리μΌμ΄μ μ μ νΈλ©λλ€. - Twisted: PythonμΌλ‘ μμ±λ μ΄λ²€νΈ κΈ°λ° λ€νΈμνΉ μμ§μ λλ€. Twistedλ λ€μν νλ‘ν μ½ λ° λμμ± λͺ¨λΈμ λν μ§μμ ν¬ν¨νμ¬ λ€νΈμν¬ μ ν리μΌμ΄μ ꡬμΆμ μν νλΆν κΈ°λ₯ μΈνΈλ₯Ό μ 곡ν©λλ€.
- Tornado: Python μΉ νλ μμν¬ λ° λΉλκΈ° λ€νΈμνΉ λΌμ΄λΈλ¬λ¦¬μ λλ€. Tornadoλ λ§μ μμ λμ μ°κ²°μ μ²λ¦¬νλλ‘ μ€κ³λμμΌλ©° μ’ μ’ μ€μκ° μΉ μ ν리μΌμ΄μ μ ꡬμΆνλ λ° μ¬μ©λ©λλ€.
- ZeroMQ: κ³ μ±λ₯ λΉλκΈ° λ©μμ§ λΌμ΄λΈλ¬λ¦¬μ λλ€. ZeroMQλ λΆμ° μμ€ν λ° λ©μμ§ νλ₯Ό ꡬμΆνλ κ°λ¨νκ³ ν¨μ¨μ μΈ λ°©λ²μ μ 곡ν©λλ€.
κ²°λ‘
Pythonμ SocketServer
λͺ¨λμ λ€νΈμν¬ νλ‘κ·Έλλ°μ λν κ·μ€ν μκ°λ₯Ό μ 곡νμ¬ λΉκ΅μ μ½κ² κΈ°λ³Έ μμΌ μλ²λ₯Ό ꡬμΆν μ μλλ‘ ν©λλ€. μμΌ, TCP/UDP νλ‘ν μ½ λ° SocketServer
μ ν리μΌμ΄μ
μ ꡬ쑰μ λν ν΅μ¬ κ°λ
μ μ΄ν΄νλ κ²μ λ€νΈμν¬ κΈ°λ° μ ν리μΌμ΄μ
μ κ°λ°νλ λ° λ§€μ° μ€μν©λλ€. SocketServer
κ° νΉν λμ νμ₯μ± λλ μ±λ₯μ΄ νμν μλ리μ€μ μ ν©νμ§ μμ μ μμ§λ§ λ³΄λ€ κ³ κΈ λ€νΈμνΉ κΈ°μ μ λ°°μ°κ³ asyncio
, Twisted λ° Tornadoμ κ°μ λ체 νλ μμν¬λ₯Ό νμνκΈ° μν κ°λ ₯ν κΈ°λ° μν μ ν©λλ€. μ΄ κ°μ΄λμ μ€λͺ
λ μμΉμ λ§μ€ν°νλ©΄ κ΄λ²μν λ€νΈμν¬ νλ‘κ·Έλλ° λ¬Έμ μ λμ²ν μ μμ΅λλ€.
κ΅μ μ κ³ λ € μ¬ν
μ μΈκ³ μ¬μ©μλ₯Ό μν μμΌ μλ² μ ν리μΌμ΄μ μ κ°λ°ν λλ λ€μ κ΅μ ν(i18n) λ° νμ§ν(l10n) μμλ₯Ό κ³ λ €νλ κ²μ΄ μ€μν©λλ€.
- λ¬Έμ μΈμ½λ©: μλ²κ° UTF-8κ³Ό κ°μ λ€μν λ¬Έμ μΈμ½λ©μ μ§μνμ¬ λ€μν μΈμ΄μ ν μ€νΈ λ°μ΄ν°λ₯Ό μ¬λ°λ₯΄κ² μ²λ¦¬νλμ§ νμΈν©λλ€. λ΄λΆμ μΌλ‘ μ λμ½λλ₯Ό μ¬μ©νκ³ ν΄λΌμ΄μΈνΈμ λ°μ΄ν°λ₯Ό λ³΄λΌ λ μ μ ν μΈμ½λ©μΌλ‘ λ³νν©λλ€.
- μκ°λ: νμμ€ν¬νλ₯Ό μ²λ¦¬νκ³ μ΄λ²€νΈλ₯Ό μμ½ν λ μκ°λλ₯Ό μΌλμ λμμμ€.
pytz
μ κ°μ μκ°λλ₯Ό μΈμνλ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ λ€λ₯Έ μκ°λ κ°μ λ³νν©λλ€. - μ«μ λ° λ μ§ νμ: λ‘μΌμΌ μΈμ νμμ μ¬μ©νμ¬ μ«μλ₯Ό νμνκ³ λ€λ₯Έ μ§μμ λ§λ μ¬λ°λ₯Έ νμμΌλ‘ λ μ§λ₯Ό νμν©λλ€. Pythonμ
locale
λͺ¨λμ μ΄ μ©λλ‘ μ¬μ©ν μ μμ΅λλ€. - μΈμ΄ λ²μ: μλ²μ λ©μμ§ λ° μ¬μ©μ μΈν°νμ΄μ€λ₯Ό μ¬λ¬ μΈμ΄λ‘ λ²μνμ¬ λ λ§μ μ¬μ©μκ° μ‘μΈμ€ν μ μλλ‘ ν©λλ€.
- ν΅ν μ²λ¦¬: κΈμ΅ κ±°λλ₯Ό μ²λ¦¬ν λλ μλ²κ° λ€μν ν΅νλ₯Ό μ§μνκ³ μ¬λ°λ₯Έ νμ¨μ μ¬μ©νλμ§ νμΈν©λλ€.
- λ²λ₯ λ° κ·μ μ€μ: λ°μ΄ν° κ°μΈ μ 보 보νΈλ²(μ: GDPR)κ³Ό κ°μ΄ μλ² μ΄μμ μ μ©λ μ μλ λ²λ₯ λλ κ·μ μꡬ μ¬νμ μμ§νμμμ€.
μ΄λ¬ν κ΅μ ν κ³ λ € μ¬νμ ν΄κ²°ν¨μΌλ‘μ¨ μ μΈκ³ μ¬μ©μκ° μ‘μΈμ€ν μ μκ³ μ¬μ©μ μΉνμ μΈ μμΌ μλ² μ ν리μΌμ΄μ μ λ§λ€ μ μμ΅λλ€.